#include <gtest/gtest.h>

#include "helper/unittest/Tracer.h"

#include "helper/sqlite/QueryResult.h"


#include "MemoryDBTest.h"
class SqliteShortcutStreamTest : public test::EmptyMemoryDBTest {
};

#include "helper/sqlite/stream/Action.h"
TEST_F(SqliteShortcutStreamTest, action){
  helper::sqlite::stream::Action action;
  {
    const char * sql = "create table if not exists tab1 (one text primary key, two int);";
    auto && r = action.db(db()).sql(sql).action();
    ASSERT_TRUE(r);
  }
}

#include "helper/sqlite/stream/Executor.h"
TEST_F(SqliteShortcutStreamTest, executor){
  helper::sqlite::stream::Executor exe;

  std::string text("3333"); //alive in executing
  int iv =  44;
  auto && fbind = [&text, iv](auto & stmt) -> std::error_code {
    if(auto && ec = stmt.textBind(1, text); ec) return ec;
    if(auto && ec = stmt.intBind(2, iv); ec) return ec;
    return std::error_code();
  };

  auto && r = exe.db(db())
    .sql("insert into tab1 values (?, ?);")
    .fbind(fbind)
    .execute();
  ASSERT_TRUE(r);
}


#include "helper/sqlite/stream/Query.h"
#include "helper/sqlite/stream/Scalar.h"

TEST_F(SqliteShortcutStreamTest, queryScalar){
  helper::sqlite::stream::Query query;  

  std::string text("1111");
  auto && fbind = [&text](auto & stmt){
    if(auto && ec = stmt.textBind(1, text); ec){
      return ec;
    }
    return std::error_code();
  };

  helper::sqlite::QueryResult && r = query.db(db())
    .sql("select count(1) from tab1 where one > ?;")
    .fbind(fbind)
    .queryScalar();
  ASSERT_TRUE(r);

  std::error_code ec;
  ASSERT_TRUE(!ec && "1" == helper::sqlite::stream::Scalar(r).text(ec).value());
  ASSERT_TRUE(!ec && "1" == helper::sqlite::stream::Scalar(r).binary(ec).value());
  ASSERT_TRUE(!ec && 1.0 == helper::sqlite::stream::Scalar(r).real(ec).value());
  ASSERT_TRUE(!ec && 1   == helper::sqlite::stream::Scalar(r).integer(ec).value());
}


#include "helper/sqlite/stream/Query.h"
#include "helper/sqlite/stream/Vector.h"

TEST_F(SqliteShortcutStreamTest, queryVector){
  helper::sqlite::stream::Query query;

  std::string text("1111");
  auto && fbind = [&text](auto & stmt){
    if(auto && ec = stmt.textBind(1, text); ec){
      return ec;
    }
    return std::error_code();
  };

  { //Vector::RowIterator
    helper::sqlite::QueryResult && r = query.db(db())
      .sql("select * from tab1 where one > ?;")
      .fbind(fbind)
      .queryVector();
    ASSERT_TRUE(r);

    EXPECT.reset()
      .pair("rowid", 0).pair("colid", 0).pair("value", "3333").pair("max_col_id", 2)
      .pair("rowid", 0).pair("colid", 1).pair("value", "44").pair("max_col_id", 2)
      ;
    TRACER.reset();
    // r must be alive 
    auto && ec = helper::sqlite::stream::Vector(r)
      .rows()->foreach([](auto & row){
        size_t cc = row->columnCount();
        for( size_t i = 0; i < cc; ++i){
          TRACER.pair("rowid",row->index())
            .pair("colid", i)
            .pair("value", row->value(i).string())
            .pair("max_col_id", cc)
            ;
        }
        return std::error_code();
      });
    ASSERT_TRUE(!ec);
    ASSERT_EQ(EXPECT, TRACER);
  }

  { //Vector::RoomIterator
    helper::sqlite::QueryResult && r = query.db(db())
      .sql("select * from tab1 where one > ?;")
      .fbind(fbind)
      .queryVector();
    ASSERT_TRUE(r);

    EXPECT.reset()
      .pair("rowid", 0).pair("colid", 0).pair("value", "3333").pair("max_col_id", 2)
      .pair("rowid", 0).pair("colid", 1).pair("value", "44").pair("max_col_id", 2)
      ;
    TRACER.reset();
    auto && ec = helper::sqlite::stream::Vector(r)
      .rooms()->foreach([](auto & room){
        TRACER.pair("rowid", room->rowid())
          .pair("colid", room->colid())
          .pair("value", room->value().string())
          .pair("max_col_id", room->columnCount())
          ;
        return std::error_code();
        }); //-> error to break;
    ASSERT_TRUE(!ec);
    ASSERT_EQ(EXPECT, TRACER);
  }
}
